wayland: fill in refresh_interval in GdkFrameTimings
authorOwen W. Taylor <otaylor@fishsoup.net>
Thu, 25 Apr 2013 15:19:31 +0000 (11:19 -0400)
committerOwen W. Taylor <otaylor@fishsoup.net>
Thu, 25 Apr 2013 17:50:01 +0000 (13:50 -0400)
Track the outputs that a window is on, and use the refresh rate from
a random one of those outputs for the refresh_interval in
GdkFrameTimings.

https://bugzilla.gnome.org/show_bug.cgi?id=698864

gdk/wayland/gdkprivate-wayland.h
gdk/wayland/gdkscreen-wayland.c
gdk/wayland/gdkwindow-wayland.c

index 5ce3deb488c2b819618308f8b3f70dc275fb4890..7aefedb25375cd8bb8c115c78dddea2e9a194112 100644 (file)
@@ -164,6 +164,8 @@ void _gdk_wayland_screen_add_output (GdkScreen        *screen,
                                      struct wl_output *output);
 void _gdk_wayland_screen_remove_output (GdkScreen *screen,
                                         guint32 id);
+int _gdk_wayland_screen_get_output_refresh_rate (GdkScreen        *screen,
+                                                 struct wl_output *output);
 
 void _gdk_wayland_display_manager_add_display (GdkDisplayManager *manager,
                                               GdkDisplay        *display);
index 7153eaf7b116a7d85f06153fa0241a0ec3dfbfb2..5d621bbb98964647e9e6b949323a683c027f8df0 100644 (file)
@@ -87,6 +87,7 @@ struct _GdkWaylandMonitor
   int          height_mm;
   char *       output_name;
   char *       manufacturer;
+  int          refresh_rate;
 };
 
 G_DEFINE_TYPE (GdkWaylandScreen, _gdk_wayland_screen, GDK_TYPE_SCREEN)
@@ -917,6 +918,7 @@ output_handle_mode(void *data,
 
   monitor->geometry.width = width;
   monitor->geometry.height = height;
+  monitor->refresh_rate = refresh;
 
   g_signal_emit_by_name (monitor->screen, "monitors-changed");
   update_screen_size (monitor->screen);
@@ -965,3 +967,21 @@ _gdk_wayland_screen_remove_output (GdkScreen *screen,
         }
     }
 }
+
+int
+_gdk_wayland_screen_get_output_refresh_rate (GdkScreen        *screen,
+                                             struct wl_output *output)
+{
+  GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
+  int i;
+
+  for (i = 0; i < screen_wayland->monitors->len; i++)
+    {
+      GdkWaylandMonitor *monitor = screen_wayland->monitors->pdata[i];
+
+      if (monitor->output == output)
+        return monitor->refresh_rate;
+    }
+
+  return 0;
+}
index e1a490ecbf87d671a60bb5121e1dbff588cec8e0..32c23e762067022ce66ec55513648e6271c85bcd 100644 (file)
@@ -96,6 +96,9 @@ struct _GdkWindowImplWayland
 
   GdkCursor *cursor;
 
+  /* The wl_outputs that this window currently touches */
+  GSList *outputs;
+
   struct wl_surface *surface;
   struct wl_shell_surface *shell_surface;
   unsigned int mapped : 1;
@@ -267,6 +270,7 @@ frame_callback (void               *data,
 {
   GdkWindow *window = data;
   GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+  GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
   GdkFrameClock *clock = gdk_window_get_frame_clock (window);
   GdkFrameTimings *timings;
 
@@ -279,6 +283,17 @@ frame_callback (void               *data,
   if (timings == NULL)
     return;
 
+  timings->refresh_interval = 16667; /* default to 1/60th of a second */
+  if (impl->outputs)
+    {
+      /* We pick a random output out of the outputs that the window touches
+       * The rate here is in milli-hertz */
+      int refresh_rate = _gdk_wayland_screen_get_output_refresh_rate (wayland_display->screen,
+                                                                      impl->outputs->data);
+      if (refresh_rate != 0)
+        timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate;
+    }
+
   timings->complete = TRUE;
 
 #ifdef G_ENABLE_DEBUG
@@ -712,6 +727,28 @@ gdk_wayland_window_map (GdkWindow *window)
     }
 }
 
+static void
+surface_enter (void *data,
+               struct wl_surface *wl_surface,
+               struct wl_output *output)
+{
+  GdkWindow *window = GDK_WINDOW (data);
+  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
+  impl->outputs = g_slist_prepend (impl->outputs, output);
+}
+
+static void
+surface_leave (void *data,
+               struct wl_surface *wl_surface,
+               struct wl_output *output)
+{
+  GdkWindow *window = GDK_WINDOW (data);
+  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
+  impl->outputs = g_slist_remove (impl->outputs, output);
+}
+
 static void
 shell_surface_handle_configure(void *data,
                                struct wl_shell_surface *shell_surface,
@@ -760,6 +797,11 @@ shell_surface_ping (void                    *data,
   wl_shell_surface_pong(shell_surface, serial);
 }
 
+static const struct wl_surface_listener surface_listener = {
+  surface_enter,
+  surface_leave
+};
+
 static const struct wl_shell_surface_listener shell_surface_listener = {
   shell_surface_ping,
   shell_surface_handle_configure,
@@ -775,6 +817,8 @@ gdk_wayland_window_create_surface (GdkWindow  *window)
   impl->surface = wl_compositor_create_surface (display_wayland->compositor);
 
   wl_surface_set_user_data(impl->surface, window);
+  wl_surface_add_listener(impl->surface,
+                          &surface_listener, window);
 }
 
 static void
@@ -838,6 +882,9 @@ gdk_wayland_window_hide_surface (GdkWindow *window,
         {
           wl_surface_destroy(impl->surface);
           impl->surface = NULL;
+
+          g_slist_free (impl->outputs);
+          impl->outputs = NULL;
         }
       impl->shell_surface = NULL;
       cairo_surface_destroy(impl->server_surface);